package kernel.udp.invoke;

	
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Hashtable;

public class UDPClient {

	
	   Hashtable<Long, Object> Responses = new Hashtable<Long, Object> ();	
	   
	   InetAddress IPAddress;
	   DatagramSocket clientSocket;
	   
	   byte[] sendData = new byte[4096];
	   byte[] receiveData = new byte[4096];	   
	   
	   long reqNo = 0;
	   
	   String hostname;
	   int Port;
	   
	   public UDPClient(XmlRpcClientConfigImpl myConfig){
		   Port = myConfig.Port;
		   hostname = myConfig.Address;
		   		   
	   }

	   public void setConfig(XmlRpcClientConfigImpl myConfig){
		   Port = myConfig.Port;
		   hostname = myConfig.Address;
		   
	   }
	   
	   public UDPClient(String Hostname, int port){
   
		   Port = port;
		   hostname = Hostname;
		   try{
			   
			   clientSocket = new DatagramSocket();
			   IPAddress = InetAddress.getByName(hostname);			   
			   
		   }
		   catch(Exception e){
			   e.printStackTrace();
		   }
		   
	   }
	   
	   public Object execute(String MthdName, Object[] Parameters){
		   
		   String requestString = MthdName;
		   
			for (int i=0; i<Parameters.length; i++){
				
				if (Parameters[i] instanceof String)
					requestString += "<|>"+"String-"+(String)Parameters[i];
				else if (Parameters[i] instanceof Integer)
					requestString += "<|>"+"Integer-"+((Integer)Parameters[i]).toString();
				else if (Parameters[i] instanceof Double)
					requestString += "<|>"+"Double-"+((Double)Parameters[i]).toString();
				else if (Parameters[i] instanceof Boolean)
					requestString += "<|>"+"Boolean-"+((Boolean)Parameters[i]).toString();
			}
				   
		   Object ans = invoke(requestString);
		   
		   
		   return ans;
		   
	   }
	   
			   
	   
	   public Object invoke(String request){

		   try{
			   
			   clientSocket = new DatagramSocket();
			   IPAddress = InetAddress.getByName(hostname);			   
			   
		   }
		   catch(Exception e){
			   e.printStackTrace();
		   }
		   
		   
		   
		   try{
			   
			   System.out.println("[ "+"UDP CLIENT"+" ] "+"[ Outgoing ] [ Dest.  = "+hostname+":"+Port+" ] [ Request Contents = "+ request+" ]");
			   
			   String TrimResponse="";
			   boolean doneFlag=false;
			   clientSocket.setSoTimeout(10000);
			   reqNo++;
			   
			   long myReqNo = reqNo;
			   
			  // while (!doneFlag){
 
				   
				   String sentence = reqNo+"<|>"+request+"<?><?><?>";
				   sendData = sentence.getBytes();
				   DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, Port);
				
				   clientSocket.send(sendPacket);
				   DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
				
				   try{
					   clientSocket.receive(receivePacket);
					   TrimResponse = new String(receivePacket.getData()).trim();
					   long msgID = toMsgID(TrimResponse);
					   if (msgID < myReqNo){
						   doneFlag=false;
						   return null;
					   }
					   else
						   doneFlag=true;
					   
				   }
				   catch (Exception e){
					   System.err.println("[ "+"UDP CLIENT"+" ] "+"UDP Packet loss: Re-sending..");
					   return null;
				   }
				   
				   
			   //}			   
			   clientSocket.close();
			   //System.out.println("[ "+kernel.udp.config.config.resourceName+" ] "+"FROM SERVER: " + TrimResponse);
			   Object ResponseObj = parseReceiveMsg(TrimResponse);
			   String Response = ResponseObj.toString();
			   System.out.println("[ "+"UDP CLIENT"+" ] "+"[ Incoming ] [ Source = " + hostname+":"+Port+" ] [ Replied Contents = " + Response+" ]\n");
			   clientSocket.close();

			   return Response;
			   
		   }
		   catch (IOException e){
			   e.printStackTrace();
			   clientSocket.close();
			   
			   return null;
		   }

		   
	   }
	   
	   public Object parseReceiveMsg(String receiveData){
		   
		   Object myObject=null;
		   long reqNo = new Long(receiveData.substring(0, receiveData.indexOf(";")));
		   receiveData = receiveData.substring(receiveData.indexOf(";")+1);
		   
		   if (receiveData.startsWith("String-")){
			   receiveData = receiveData.substring(receiveData.indexOf("-")+1);			   
			   myObject = receiveData;
		   }
		   else if (receiveData.startsWith("Integer-")){
			   receiveData = receiveData.substring(receiveData.indexOf("-")+1);			   
			   myObject = new Integer(receiveData);
			   
		   }
		   else if (receiveData.startsWith("Double-")){
			   receiveData = receiveData.substring(receiveData.indexOf("-")+1);			   
			   myObject = new Double(receiveData);
			   
		   }
		   else if (receiveData.startsWith("Boolean-")){
			   receiveData = receiveData.substring(receiveData.indexOf("-")+1);			   
			   myObject = new Boolean(receiveData);
			   
		   }
		   return myObject;
		   
	   }
	   
	   public long toMsgID(String receiveData){
		   
		   long reqNo = new Long(receiveData.substring(0, receiveData.indexOf(";")));
		   return reqNo;
		   
	   }
	   
	   public void close(){
	      clientSocket.close();
	   }	   
	   
	   
}	
	

